
1.  const
	<1> 修饰变量，说明该变量不可以被改变
	<2> 修饰指针，分为指向常量的指针和指针常量
	<3> 常量引用，经常用于函数的形参，即避免了拷贝，又避免了函数对值的修改
	<4> 修饰类中的成员函数，说明该成员函数内不能修改该类中成员变量

// 这项语法并不像看上去那么反复无常，如果关键字const出现在星号的左侧，那么指针指向的内容为const,
// 如果关键字const出现在星号的右侧，那么指针本身是const;如果星号出现在两侧，那么两者都为const.

// STL迭代器是模仿的指针，因此迭代器的行为非常像一个指针，声明一个迭代器的const就像声明一个指针的const: 
// 迭代器不允许指向不同的东西，但迭代器指向的东西是可以改变的。如果你想让迭代器指向的东西不能被修改，这时你就需要一个const_iterator.
// Const 成员函数介绍
// 将const作用于成员函数上面的意图是能够确认哪些成员函数可以通过const对象被调用。
// 这类成员函数很重要，原因有两条：
// 一，它们使得类的接口更容易被理解，知道哪些函数可以改变对象哪些不可以，这一点很重要。
// 二，它们使得和const对象一起工作成为可能，这是编写高效代码的很重要的方面，
// 因为Item20解释道，提高c++程序性能的基本方法是按const引用传递对象。这项是可行的前提是，const成员函数能够处理const修饰的对象。


		//类 
		class A{
		private:
			const int a;        // 常成员变量，只能在初始化列表赋值
		public:
			A();
			A(int x) :a(x) {};  // 初始化列表

			int getValue();         // 普通成员函数
			int getValue() const;   // 常成员函数，不得修改类中的任何数据成员的值
		};

		void function() {
			//对象
			A b;				// 普通对象，可以调用全部成员函数
			const A a;			// 常对象，只能调用常成员函数、更新常成员变量
			const A *p = &a;	// 常指针 
			const A &q = a;		// 常引用
			//指针
			char greeting[] = "Hello";				
			char *p1 = greeting;					// 指针变量，指向字符数组变量
			const char *p2 = greeting;				// 指针变量，指向字符数组常量
			char* const p3 = greeting;				// 常指针，指向字符数组变量
			const char * const p4 = greeting;		// 常指针，指向字符数组常量
		}


	void function1(const int var);		 // 传递过来的参数在函数内不可变
	void function2(const char * var);	 // 参数指针所指内容为常量
	void function3(char * const var);	 // 参数指针为常指针
	void function4(const int &var);		 // 引用参数在函数内为常量  //常引用

	const int function5();			    // 返回一个常数
	const int * function6();		    // 返回一个指向常量的指针变量，使用：const int *p = function6();
	int * const function7();		    // 返回一个指向变量的常指针，使用：int* const p = function7();


2. static
	<1> 修饰普通变量，修改变量的存储区域和生命周期，使变量存储在静态区，在 main 函数运行前就分配了空间，如果有初始值就用初始值初始化它，如果没有初始值系统用默认值初始化它。
	<2> 修饰普通函数，表明函数的作用范围，仅在定义该函数的文件内才能使用。在多人开发项目时，为了防止与他人命令函数重名，可以将函数定位为 static。
	<3> 修饰成员变量，修饰成员变量使所有的对象只保存一个该变量，而且不需要生成对象就可以访问该成员。
	<4> 修饰成员函数，修饰成员函数使得不需要生成对象就可以访问该函数，但是在 static 函数内不能访问非静态成员。	
	
	static int n;
	static void fn();

3. 	this 指针
	this 指针是一个隐含于每一个非静态成员函数中的特殊指针。它指向正在被该成员函数操作的那个对象。
	当对一个对象调用成员函数时，编译程序先将对象的地址赋给 this 指针，然后调用成员函数，每次成员函数存取数据成员时，由隐含使用 this 指针。
	当一个成员函数被调用时，自动向它传递一个隐含的参数，该参数是一个指向这个成员函数所在的对象的指针。
	this 指针被隐含地声明为: ClassName *const this，这意味着不能给 this 指针赋值；在 ClassName 类的 const 成员函数中，this 指针的类型为：const ClassName* const，
	这说明不能对 this 指针所指向的这种对象是不可修改的（即不能对这种对象的数据成员进行赋值操作）；
	this 并不是一个常规变量，而是个右值，所以不能取得 this 的地址（不能 &this）。
	在以下场景中，经常需要显式引用 this 指针：
	为实现对象的链式引用；
	为避免对同一对象进行赋值操作；
	在实现一些数据结构时，如 list。
	
4. 	inline 内联函数
			<1> 相当于把内联函数里面的内容写在调用内联函数处；
			<2> 相当于不用执行进入函数的步骤，直接执行函数体；
			<3> 相当于宏，却比宏多了类型检查，真正具有函数特性；
			<4> 不能包含循环、递归、switch 等复杂操作；
			<5> 在类声明中定义的函数，除了虚函数的其他函数都会自动隐式地当成内联函数。	

			编译器对 inline 函数的处理步骤
			将 inline 函数体复制到 inline 函数调用点处；
			为所用 inline 函数中的局部变量分配内存空间；
			将 inline 函数的的输入参数和返回值映射到调用方法的局部变量空间中；
			如果 inline 函数有多个返回点，将其转变为 inline 函数代码块末尾的分支（使用 GOTO）

	inline int functionName(int a, int b);    //声明
	inline int functionName(int a, int b) {};  //定义

	class A {
		int doA() { return 0; } //隐式内联
	};

	class B {
		int doA();
	};
	inline int A::doA() { return 0; } //需要显式内联
 
5. assert()
	断言，是宏，而非函数。assert 宏的原型定义在 <assert.h>（C）、<cassert>（C++）中，
	其作用是如果它的条件返回错误，则终止程序执行。可以通过定义 NDEBUG 来关闭 assert，但是需要在源代码的开头，include <assert.h> 之前

	# define NDEBUG    // 加上这行，则 assert 不可用
	#include <cassert>
		assert(p != NULL);

6. sizeof()
		sizeof 对数组，得到整个数组所占空间大小。
		sizeof 对指针，得到指针本身所占空间大小。
	
7. pragma pack (n)
		设定结构体、联合以及类成员变量以 n 字节方式对齐	

	#pragma pack(push)   // 保存对齐状态
	#pragma pack(4)      // 设定为 4 字节对齐
		struct Test {
			char m1;
			double m4;
			int m3;
		};
	#pragma pack(pop);	// 恢复对齐状态


9. 		volatile 关键字是一种类型修饰符，用它声明的类型变量表示可以被某些编译器未知的因素（操作系统、硬件、其它线程等）更改。所以使用 volatile 告诉编译器不应对这样的对象进行优化。
		volatile 关键字声明的变量，每次访问时都必须从内存中取出值（没有被 volatile 修饰的变量，可能由于编译器的优化，从 CPU 寄存器中取值）
		const 可以是 volatile （如只读的状态寄存器）
		指针可以是 volatile	
		用volatile关键字声明的变量i每一次被访问时，执行部件都会从i相应的内存单元中取出i的值
	volatile int i = 10;
	
	1) 中断服务程序中修改的供其它程序检测的变量需要加volatile； 
	2) 多任务环境下各任务间共享的标志应该加volatile； 
	3) 存储器映射的硬件寄存器通常也要加volatile说明，因为每次对它的读写都可能由不同意义；


10. 	extern "C"
		被 extern 限定的函数或变量是 extern 类型的
		被 extern "C" 修饰的变量和函数是按照 C 语言方式编译和连接的
		extern "C" 的作用是让 C++ 编译器将 extern "C" 声明的代码当作 C 语言代码处理，可以避免 C++ 因符号修饰导致代码不能和C语言库中的符号进行链接的问题。

		#ifdef __cplusplus
			extern "C" {
		#endif
				void *memset(void *, int, size_t);
		#ifdef __cplusplus
			}
		#endif


11. 		C++ 中 struct 和 class
			总的来说，struct 更适合看成是一个数据结构的实现体，class 更适合看成是一个对象的实现体。
			区别:
			最本质的一个区别就是默认的访问控制
			默认的继承访问权限。struct 是 public 的，class 是 private 的。
			struct 作为数据结构的实现体，它默认的数据访问控制是 public 的，而 class 作为对象的实现体，它默认的成员变量访问控制是 private 的。

12. explicit 修饰的构造函数可用来防止隐式转换
// explicit 关键字是为了解决隐式类型转换而特别引入的这个特性。如果构造函数用explicit声明，编译器会拒绝为了隐式类型转换而调用构造函数。显式类型转换依然合法。

		class Test1 {
		public:
			Test1(int n) {
				num = n;
			}
		private:
			int num;
		};

		class Test2 {
		public:
			explicit Test2(int n) {
				num = n;
			}
		private:
			int num;
		};

		Test1 t1 = 1;	// 隐式调用其构造函数，成功
		Test2 t2 = 1;	// 编译错误，不能隐式调用其构造函数
		Test2 t3(1);    // 显式调用成功

13. enum 枚举类型
	限定作用域的枚举类型
	enum class open_modes { input, output, append };
	不限定作用域的枚举类型
	enum color { red, yellow, green };
	enum { floatPrec = 6, doublePrec = 10 };
	
14. decltype (expression)
	decltype 关键字用于检查实体的声明类型或表达式的类型及值分类	

	template <typename It>
	auto fcn(It begin, It end) -> decltype(*begin) {
		return *begin;
	}


15. 成员初始化列表
		更高效：少了一次调用默认构造函数的过程
		有些场合必须要用初始化列表：
			常量成员，因为常量只能初始化不能赋值，所以必须放在初始化列表里面
			引用类型，引用必须在定义的时候初始化，并且不能重新赋值，所以也要写在初始化列表里面
			没有默认构造函数的类类型，因为使用初始化列表可以不必调用默认构造函数来初始化，而是直接调用复制构造函数初始化。

	// 这个构造函数会和上面的构造函数产生同样的结果。但是它会更有效率。
// 基于赋值的版本首先会调用默认构造函数来初始化theName,theAddress和thePhones,然后迅速的在默认构造出来的成员基础之上再进行赋值。
// 在默认构造函数中进行的所有工作因此被浪费了。成员初始化列表的使用避免了这个问题，因为成员初始化列表中的参数被用作不同数据成员的构造函数的参数。
// 在这种情况下，theName会以name作为参数拷贝构造出来，theAddress会以address作为参数拷贝构造出来，theAddress会以phones为参数拷贝构造出来。
// 对于大多数类型，比起先调用默认构造函数然后调用拷贝赋值运算符，调用一个单一拷贝构造函数是更有效率的，而且有时效率能够大大提高。
	
16. 面向对象三大特征 —— 封装、继承、多态
		封装:
			把客观事物封装成抽象的类，并且类可以把自己的数据和方法只让可信的类或者对象操作，对不可信的进行信息隐藏。
			关键字：public, protected, friendly, private。不写默认为 friendly
			因为只有成员函数和友元函数能够访问private成员, protected的成员,派生类也可以访问,
		继承:
			基类（父类）——> 派生类（子类）
		多态:
			多态，即多种状态，在面向对象语言中，接口的多种不同的实现方式即为多态。
		C++ 多态有两种：静态多态（早绑定）、动态多态（晚绑定）。静态多态是通过函数重载实现的；动态多态是通过虚函数实现的。
		多态是以封装和继承为基础的。

		动态多态（晚绑定）
		虚函数：用 virtual 修饰成员函数，使其成为虚函数
		注意：
		普通函数（非类成员函数）不能是虚函数
		静态函数（static）不能是虚函数
		构造函数不能是虚函数（因为在调用构造函数时，虚表指针并没有在对象的内存空间中，必须要构造函数调用完成后才会形成虚表指针）
		内联函数不能是表现多态性时的虚函数

		纯虚函数:
		纯虚函数是一种特殊的虚函数，在基类中不能对虚函数给出有意义的实现，而把它声明为纯虚函数，它的实现留给该基类的派生类去做。
		virtual int A() = 0;


17.		虚函数、纯虚函数
		类里如果声明了虚函数，这个函数是实现的，哪怕是空实现，它的作用就是为了能让这个函数在它的子类里面可以被覆盖，这样的话，这样编译器就可以使用后期绑定来达到多态了。
		纯虚函数只是一个接口，是个函数的声明而已，它要留到子类里去实现。
		虚函数在子类里面也可以不重载的；但纯虚函数必须在子类去实现。
		虚函数的类用于 “实作继承”，继承接口的同时也继承了父类的实现。当然大家也可以完成自己的实现。纯虚函数关注的是接口的统一性，实现由子类完成。
		带纯虚函数的类叫抽象类，这种类不能直接生成对象，而只有被继承，并重写其虚函数后，才能使用。  因此客户不能创建抽象类的实例，而只有它的派生类才可以
	
		抽象类被继承后，子类可以继续是抽象类，也可以是普通类，
		虚函数指针、虚函数表:
		虚函数指针：在含有虚函数类的对象中，指向虚函数表，在运行时确定。
		虚函数表：在程序只读数据段（.rodata section，见：目标文件存储结构），存放虚函数指针，如果派生类实现了基类的某个虚函数，则在虚表中覆盖原本基类的那个虚函数指针，在编译时根据类的声明创建。
		虚继承:
		虚继承用于解决多继承条件下的菱`
		底层实现原理与编译器相关，一般通过虚基类指针和虚基类表实现，每个虚继承的子类都有一个虚基类指针（占用一个指针的存储空间，4字节）和虚基类表（不占用类对象的存储空间）
		（需要强调的是，虚基类依旧会在子类里面存在拷贝，只是仅仅最多存在一份而已，并不是不在子类里面了）；当虚继承的子类被当做父类继承时，虚基类指针也会被继承。

		实际上，vbptr 指的是虚基类表指针（virtual base table pointer），该指针指向了一个虚基类表（virtual table），虚表中记录了虚基类与本类的偏移地址；
		通过偏移地址，这样就找到了虚基类成员，而虚继承也不用像普通多继承那样维持着公共基类（虚基类）的两份同样的拷贝，节省了存储空间。

		虚继承、虚函数：
		相同之处：都利用了虚指针（均占用类的存储空间）和虚表（均不占用类的存储空间）
		不同之处：
		虚继承
		虚基类依旧存在继承类中，只占用存储空间
		虚基类表存储的是虚基类相对直接继承类的偏移
		虚函数：
		虚函数不占用存储空间
		虚函数表存储的是虚函数地址
		模板类、成员模板、虚函数：
		模板类中可以使用虚函数
		一个类（无论是普通类还是类模板）的成员模板（本身是模板的成员函数）不能是虚函数
		抽象类、接口类、聚合类
		抽象类：含有纯虚函数的类
		接口类：仅含有纯虚函数的抽象类
		聚合类：用户可以直接访问其成员，并且具有特殊的初始化语法形式。满足如下特点：
		所有成员都是 public
		没有有定于任何构造函数
		没有类内初始化
		没有基类，也没有 virtual 函数


	class C {
	public:
		void function_1(int a);
		void function_1(int a, int b); //静态多态（早绑定） //函数重载	};


	//动态多态使用
	class Shape {
	public:
		Shape();							    // 构造函数不能是虚函数
		virtual double calcArea() {};
		virtual  ~Shape();						// 虚析构函数,虚析构函数是为了解决基类的指针指向派生类对象，并用基类的指针删除派生类对象
	};

	class Circle :public Shape {
	public:
		virtual double calcArea();
	};


18.面向对象的程序设计思想是什么？
	答：把数据结构和对数据结构进行操作的方法封装形成一个个的对象

19.什么是类？
	把一些具有共性的对象归类后形成一个集合，也就是所谓的类
	
20.对象都具有的两方面特征是什么？分别是什么含义？
	答：对象都具有的特征是：静态特征和动态特征
		静态特征是指能描述对象的一些属性（成员变量），动态特征是指对象表现出来的行为（成员函数）
		
21.在头文件中进行类的声明，在对应的实现文件中进行类的定义有什么意义？
	答：这样可以提高编译效率，因为分开的话只需要编译一次生成对应的.obj文件后，再次应用该类的地方，这个类就不会被再次编译，从而大大的提高了编译效率
	OBJ只给出了程序的相对地址，而可执行文件是绝对地址

22.在类的内部定义成员函数的函数体，这种函数会具备那种属性？
	答：这种函数会自动为内联函数，这种函数在函数调用的地方在编译阶段都会进行代码替换	
	
23.成员函数通过什么来区分不同对象的成员数据？为什么它能够区分？
	答：通过this指针指向对象的首地址来区分的

24. C++编译器自动为类产生的四个缺省函数是什么？
	答：默认构造函数，拷贝构造函数，析构函数，赋值函数
	什么时候空类不再是一个空类？答案是用c++处理的空类。如果你自己不声明，编译器会为你声明它们自己版本的拷贝构造函数，拷贝赋值运算符和析构函数，
	如果你一个构造函数都没有声明，编译器同样会为你声明一个默认拷贝构造函数。这些所有的函数会是public和inline的（Item30）
	
25.拷贝构造函数在哪几种情况下会被调用？
	答：  1.当类的一个对象去初始化该类的另一个对象时
         2.如果函数的形参是类的对象，调用函数进行形参和实参结合时
         3.如果函数的返回值是类对象，函数调用完成返回时
		 
26.构造函数与普通函数相比在形式上有什么不同？（构造函数的作用，它的声明形式来分析）
	答：构造函数是类的一种特殊成员函数，一般情况下，它是专门用来初始化对象成员变量的
		构造函数的名字必须与类名相同，它不具有任何类型，不返回任何值。
		
27.什么时候必须重写拷贝构造函数？
	答：当构造函数涉及到动态存储分配空间时，要自己写拷贝构造函数，并且要深拷贝
	
28.构造函数的调用顺序是什么？
	答：1.先调用基类构造函数
		2.按声明顺序初始化数据成员
		3.最后调用自己的构造函数。
		
29.哪几种情况必须用到初始化成员列表？
	答：类的成员是常量成员初始化；
		类的成员是对象成员初始化，而该对象没有无参构造函数。
		类的成员为引用时。		
		
30.什么是常对象？
	答：常对象是指在任何场合都不能对其成员的值进行修改的对象		
		
31.静态函数存在的意义？
	答：静态私有成员在类外不能被访问，可通过类的静态成员函数来访问；		
	   当类的构造函数是私有的时，不像普通类那样实例化自己，只能通过静态成员函数来调用构造函数

32.在类外有什么办法可以访问类的非公有成员？
	答：友元，继承，公有成员函数。		
		
33.什么叫抽象类？
	答：不用来定义对象而只作为一种基本类型用作继承的类		
		
34.运算符重载的意义？
	答：为了对用户自定义数据类型的数据的操作与内定义的数据类型的数据的操作形式一致		
		
35.不允许重载的5个运算符是哪些？
	答：1. .*（成员指针访问运算符号）
		2. ：：域运算符
		3. Sizeof 长度运算符号
		4. ？：条件运算符号
		5. .（成员访问符）



36.赋值运算符和拷贝构造函数的区别与联系？
	答：相同点：都是将一个对象copy到另一个中去
		不同点：拷贝构造函数涉及到要新建立一个对象

37.在哪种情况下要调用该类的析构函数？
	答：对象生命周期结束时

38.对象间是怎样实现数据的共享的？
	答：通过类的静态成员变量来实现对象间的数据共享。静态成员变量占有自己独立的空间不为某个对象所私有
	

39.对对象成员进行初始化的次序是什么？
	答：它的次序完全不受它们在初始化表中次序的影响，只有成员对象在类中声明的次序来决定的


40.是不是一个父类写了一个virtual函数，如果子类覆盖它的函数不加virtual ,也能实现多态?
	答：virtual修饰符会被隐形继承的。
		virtual可加可不加,子类覆盖它的函数不加virtual ,也能实现多态

41.函数重载是什么意思？它与虚函数的概念有什么区别？
	答：函数重载是一个同名函数完成不同的功能，编译系统在编译阶段通过函数参数个数、参数类型不同，
	函数的返回值来区分该调用哪一个函数，即实现的是静态的多态性。
	但是记住：不能仅仅通过函数返回值不同来实现函数重载。
	而虚函数实现的是在基类中通过使用关键字virtual来申明一个函数为虚函数，
	含义就是该函数的功能可能在将来的派生类中定义或者在基类的基础之上进行扩展，
	系统只能在运行阶段才能动态决定该调用哪一个函数，所以实现的是动态的多态性。
	它体现的是一个纵向的概念，也即在基类和派生类间实现

42.构造函数和析构函数是否可以被重载,为什么?
	答：构造函数可以被重载，析构函数不可以被重载。因为构造函数可以有多个且可以带参数，而析构函数只能有一个，且不能带参数


43. main函数执行以前，还会执行什么代码？
	答案：全局对象的构造函数会在main 函数之前执行

44.当一个类A中没有生命任何成员变量与成员函数,这时sizeof(A)的值是多少，如果不是零，请解释一下编译器为什么没有让它为零。（Autodesk）
	答案：肯定不是零。举个反例，如果是零的话，声明一个class A[10]对象数组，而每一个对象占用的空间是零，这时就没办法区分A[0],A[1]…了

45. delete与 delete []区别：
	答：delete只会调用一次析构函数，而delete[]会调用每一个成员的析构函数

46．子类析构时要调用父类的析构函数吗？
	答：会调用。析构函数调用的次序是先派生类的析构后基类的析构，也就是说在基类的的析构调用的时候,派生类的信息已经全部销毁了

47.继承的优缺点
	1、类继承是在编译时刻静态定义的，且可直接使用，
	2、类继承可以较方便地改变父类的实现。
	缺点：
	1、因为继承在编译时刻就定义了，所以无法在运行时刻改变从父类继承的实现
	2、父类通常至少定义了子类的部分行为，父类的任何改变都可能影响子类的行为
	3、如果继承下来的实现不适合解决新的问题，则父类必须重写或被其他更适合的类替换。这种依赖关系限制了灵活性并最终限制了复用性。

48.解释堆和栈的区别。 
	答：栈区（stack）— 由编译器自动分配释放 ，存放函数的参数值，局部变量的值等。
	    堆（heap）一般由程序员分配释放， 若程序员不释放，程序结束时可能由OS回收

49.虚拟函数与普通成员函数的区别？内联函数和构造函数能否为虚拟函数？
	答案：区别：虚拟函数有virtual关键字，有虚拟指针和虚函数表，虚拟指针就是虚拟函数的接口，而普通成员函数没有。内联函数和构造函数不能为虚拟函数

50.构造函数和析构函数的调用顺序?析构函数为什么要虚拟?
	答案：构造函数的调用顺序：基类构造函数—对象成员构造函数—派生类构造函数；
	析构函数的调用顺序与构造函数相反。析构函数虚拟是为了防止析构不彻底，造成内存的泄漏

	// 1.2非虚析构函数引入的问题
// 问题在于getTimeKeeper返回一个指向派生类对象的指针(AtomicClock),这个对象通过一个基类指针(一个TimeKeeper*指针)来进行释放（delete），
// 基类中(TimeKeeper)有一个非虚析构函数。这是造成灾难的一个因素，
// 因为c++指出：通过一个基类的指针来释放一个派生类的对象，如果基类的析构函数是非虚的，那么结果未定义。
// 在运行时有可能发生以下状况：对象的派生类部分永远不会被释放掉。如果对getTimeKeeper的调用恰巧返回一个指向AtomicClock对象的指针，
// 对象的AtomicClock部分（也就是在AtomicClock类中声明的数据成员）可能不会被释放掉，AtomicClock类的析构函数也不会被执行。
// 然而，基类部分（也就是TimeKeeper部分）是会被释放掉的，这会导致产生一个古怪的“部分被释放的”对象。这是使资源泄露，破坏数据结构和在debugger上花费大把时间的绝佳方法。

// 基类中(TimeKeeper)除了析构函数外一般情况下会包含虚函数，因为虚函数存在的目的是为了函数在派生类中的定制化实现（Item34）。
// 举个例子，TimeKeeper会有一个虚函数，getCurrentTime,这个函数在不同的派生类中会有不同的实现。任何有虚函数的类应该肯定有一个虚析构函数。

// 在类中声明虚析构函数当且仅当类中至少包含一个虚函数

51. C++中类型为private的成员变量可以由哪些函数访问?
	答：只可以由本类中的成员函数和友元函数访问

52.请说出类中private，protect，public三种访问限制类型的区别
	答：private是私有类型，只有本类中的成员函数访问;protect是保护型的，本类和继承类可以访问;public是公有类型，任何类都可以访问

53.类中成员变量怎么进行初始化？
	答：可以通过构造函数的初始化列表或构造函数的函数体实现	

54.在什么时候需要使用“常引用”？　
	答：如果既要利用引用提高程序的效率，又要保护传递给函数的数据不在函数中被改变，就应使用常引用

55.引用与指针有什么区别？
	答： 1) 引用必须被初始化，指针不必。
		 2) 引用初始化以后不能被改变，指针可以改变所指的对象。
         3) 不存在指向空值的引用，但是存在指向空值的指针

		 	char* pc = 0; // 设置指针为空值
	char& rc = *pc; // 让指针指向空值，这是非常有害的，结果将是不确定的

56.描述实时系统的基本特性
	答：在特定时间内完成特定的任务，实时性与可靠性

57.全局变量和局部变量在内存中是否有区别？如果有，是什么区别？
	答：全局变量储存在静态数据区，局部变量在堆栈中

58.堆栈溢出一般是由什么原因导致的？
	答：没有回收垃圾资源

59.什么函数不能声明为虚函数？
	答： 构造函数（constructor）

60.如何引用一个已经定义过的全局变量？
	答：可以用引用头文件的方式，也可以用extern关键字，
		如果用引用头文件方式来引用某个在头文件中声明的全局变理，假定你将那个变写错了，那么在编译期间会报错，
		如果你用extern方式引用时，假定你犯了同样的错误，那么在编译期间不会报错，而在连接期间报错

61.对于一个频繁使用的短小函数,在C语言中应用什么实现,在C++中应用什么实现?
	答：c用宏定义，c++用inline

62. C++是不是类型安全的？
	答：不是。两个不同类型的指针之间可以强制转换（用reinterpret cast)

63.简述数组与指针的区别？
	答：数组要么在静态存储区被创建（如全局数组），要么在栈上被创建。指针可以随时指向任意类型的内存块

64. C++函数中值的传递方式
	答：有三种方式：值传递、指针传递、引用传递

65.内存的分配方式
	答：分配方式有三种，
		1、 静态存储区，是在程序编译时就已经分配好的，在整个运行期间都存在，如全局变量、常量
		2、 栈上分配，函数内的局部变量就是从这分配的，但分配的内存容易有限
		3、 堆上分配，也称动态分配，如我们用new,malloc分配内存，用delete,free来释放的内存

66. extern“C”有什么作用？
	答：Extern “C”是由Ｃ＋＋提供的一个连接交换指定符号，用于告诉Ｃ＋＋这段代码是Ｃ函数。
		这是因为C++编译后库中函数名会变得很长，与C生成的不一致，造成Ｃ＋＋不能直接调用C函数，加上extren “c”后，C++就能直接调用C函数了
		Extern “C”主要使用正规DLL函数的引用和导出 和 在C++包含C函数或C头文件时使用。使用时在前面加上extern “c” 关键字即可。
		可以用一句话概括extern “C”这个声明的真实目的：实现C++与C及其它语言的混合编程

67. #include <filename.h>和 #include “filename.h”有什么区别？
	答：对于#include <filename.h> ，编译器从标准库路径开始搜索 filename.h
		对于#include “filename.h” ，编译器从用户的工作路径开始搜索 filename.h

68. 	
	16位编译器
	char ：1个字节
	char*(即指针变量): 2个字节
	short int : 2个字节
	int：  2个字节
	unsigned int : 2个字节
	float:  4个字节
	double:   8个字节
	long:   4个字节
	long long:  8个字节
	unsigned long:  4个字节	 
	 
	32位编译器
	char ：1个字节
	char*（即指针变量）: 4个字节（32位的寻址空间是2^32, 即32个bit，也就是4个字节。同理64位编译器）
	short int : 2个字节	 
	int：  4个字节
	unsigned int : 4个字节
	float:  4个字节
	double:   8个字节
	long:   4个字节
	long long:  8个字节
	unsigned long:  4个字节
	 
	64位编译器
	char ：1个字节
	char*(即指针变量): 8个字节
	short int : 2个字节
	int：  4个字节
	unsigned int : 4个字节
	float:  4个字节
	double:   8个字节
	long:   8个字节
	long long:  8个字节
	unsigned long:  8个字节
		
	
69. strcpy()和memcpy()的区别？
	答：strcpy()和memcpy()都可以用来拷贝字符串，strcpy()拷贝以’\0’结束，但memcpy()必须指定拷贝的长度


70.说明define和const在语法和含义上有什么不同？
	答： (1) #define是C语法中定义符号变量的方法，符号常量只是用来表达一个值，在编译阶段符号就被值替换了，它没有类型；
		(2) Const是C++语法中定义常变量的方法，常变量具有变量特性，它具有类型，内存中存在以它命名的存储单元，可以用sizeof测出长度
		
71.总结static的应用和作用？
	答： (1）函数体内static变量的作用范围为该函数体，不同于auto变量，该变量的内存只被分配一次，因此其值在下次调用时仍维持上次的值；
		（2）在模块内的static全局变量可以被模块内所用函数访问，但不能被模块外其它函数访问；
		（3）在模块内的static函数只可被这一模块内的其它函数调用，这个函数的使用范围被限制在声明它的模块内；
		（4）在类中的static成员变量属于整个类所拥有，对类的所有对象只有一份拷贝；
		（5）在类中的static成员函数属于整个类所拥有，这个函数不接收this指针，因而只能访问类的static成员变量。

72.总结const的应用和作用？
	答：（1）欲阻止一个变量被改变，可以使用const关键字。在定义该const变量时，通常需要对它进行初始化，因为以后就没有机会再去改变它了；
		（2）对指针来说，可以指定指针本身为const，也可以指定指针所指的数据为const，或二者同时指定为const；
		（3）在一个函数声明中，const可以修饰形参，表明它是一个输入参数，在函数内部不能改变其值；
		（4）对于类的成员函数，若指定其为const类型，则表明其是一个常函数，不能修改类的成员变量；
		（5）对于类的成员函数，有时候必须指定其返回值为const类型，以使得其返回值不为左值（不能赋值）


73. static函数与普通函数有什么区别?
	答：static函数在内存中只有一份，普通函数在每个被调用中维持一份拷贝

74.程序的局部变量存在于（栈）中，全局变量存在于（静态区 ）中，动态申请数据存在于（ 堆）中

75.什么叫静态关联，什么叫动态关联?
	答：在多态中，如果程序在编译阶段就能确定实际执行动作，则称静态关联，等到程序运行才能确定叫动态关联

76.什么叫智能指针？
	答：智能指针和普通指针的区别在于智能指针实际上是对普通指针加了一层封装机制，这样的一层封装机制的目的是为了使得智能指针可以方便的管理一个对象的生命期

77.什么时候需要用虚析构函数？
	答：当基类指针指向用new运算符生成的派生类对象时，delete基类指针时，派生类部分没有释放掉而造成释放不彻底现象，需要虚析构函数。 补充：虚函数就是让派生类调用基类的虚函数

78.什么是平衡二叉树？
	答：左右子树都是平衡二叉树，而且左右子树的深度差值的约对值不大于1

79. memset ,memcpy的区别
	答：memset用来对一段内存空间全部设置为某个字符，一般用在对定义的字符串进行初始化为’\0′
		memcpy用来做内存拷贝，你可以拿它拷贝任何数据类型的对象，可以指定拷贝的数据长度

80．已知strcpy函数的原型是：
	char * strcpy(char * strDest,const char * strSrc);
	不调用库函数，实现strcpy函数。其中，strSrc是原字符串，strDest是目标字符串 。
	答案：
		char *strcpy(char *strDest, const char *strSrc){
			if ( strDest == NULL || strSrc == NULL)
				return NULL;
			if ( strDest == strSrc)
				return strDest;
			char *tempptr = strDest; //指针tempptr指向strDest的地址；
			while( (*strDest++ = *strSrc++) != ‘\\0’){} //注意：别忘了转义符；
			return tempptr ; //返回指针向的地址；
		}


81．编写类 String 的构造函数、析构函数和赋值函数已知类 String 的原型为： 

		#include <iostream>
		class String
		{
		public:
			String(const char *str = NULL);//普通构造函数
			String(const String &str);//拷贝构造函数
			String & operator =(const String &str);//赋值函数
			~String();//析构函数
		private:
			char* m_data;//用于保存字符串
		};

		//普通构造函数
		String::String(const char *str) {
			if (str == NULL) {
				m_data = new char[1]; //对空字符串自动申请存放结束标志'\0'的空间 
				if (m_data == NULL) { //内存是否申请成功
					std::cout << "申请内存失败！" << std::endl;
					exit(1);
				}
				m_data[0] = '\0';
			}
			else {
				int length = strlen(str);
				m_data = new char[length + 1];
				if (m_data == NULL) {//内存是否申请成功
					std::cout << "申请内存失败！" << std::endl;
					exit(1);
				}
				strcpy(m_data, str);
			}
		}
		//拷贝构造函数
		String::String(const String &str) { //输入参数为const型
			int length = strlen(str.m_data);
			m_data = new char[length + 1];
			if (m_data == NULL) {//内存是否申请成功
				std::cout << "申请内存失败！" << std::endl;
				exit(1);
			}
			strcpy(m_data, str.m_data);
		}
		//赋值函数
		String& String::operator =(const String &str) {//输入参数为const型
			if (this == &str) //检查自赋值
				return *this;
			int length = strlen(str.m_data);
			delete[] m_data;//释放原来的内存资源
			m_data = new char[length + 1];
			if (m_data == NULL) {//内存是否申请成功
				std::cout << "申请内存失败！" << std::endl;
				exit(1);
			}
			strcpy(m_data, str.m_data);
			return *this;//返回本对象的引用
		}
		//析构函数
		String::~String() {
			delete[] m_data;
		}

		void main() {
			String a;
			String b("abc");
			system("pause");
		}


82.名字相同的指向不同类型的指针有什么区别?
	答：计算机的CPU决了内存寻址方式，所以，不管指针所指对象是什么类型的，指针本身的规格都一样。
		如果一个指针变量的关联类型为int，则通过指针变量访问对象时，读取从指针指示的位置开始的连续4个字节，并按整型数据解释。
		如果一个指针变量的关联类型为char,则通过指针变量访问对象时，读取指针位置的当前字节，并按字符型数据解释

83.char * a[]="nieyani"这种写法对不对?
	答：这是指针数组。表示数组元素的类型是指针类型
		指针数组说明方式为：类型 * 标识符[表达式]
		例如：int * pi[3] //数组元素是关联类型为整形的指针
					char * ps[10] //数组元素是关联类型为字符型的指针


84.static的基本用法
	当类成员冠以static声明时，称为静态成员。“静态”是指它的作用域局部于类，一个类可以创建多个对象，
	因此，静态成员提供了一种同类 对象共享的机制；“成员”是指它与普通类成员一样受不同访问特性的约束。
	1.静态数据成员：在类中声明，在类外定义。尽管static数据成员从存储性质上式全局变量，但是其作用域是类。static数据成员在类外可以用“类名：：”做限定词，或通过对象访问。
	2.静态成员函数：静态成员函数提供了一个不依赖于类数据结构的共同操作，它没有this指针。因为静态成员函数只能访问类的静态数据成员

85. C和C++的区别是什么？
	C是面向过程的语言，C++是在C语言的基础上开发的一种面向对象编程语言，应用广泛。
	C中函数不能进行重载，C++函数可以重载
	C++在C的基础上增添类，C是一个结构化语言，它的重点在于算法和数据结构。C程序的设计首要考虑的是如何通过一个过程，对输入（或环境条件）进行运算处理得到输出（或实现过程（事务）控制），
		而对于C++，首要考虑的是如何构造一个对象模型，让这个模型能够契合与之对应的问题域，这样就可以通过获取对象的状态信息得到输出或实现过程（事务）控制。
	C++中struct和class除了默认访问权限外，别的功能几乎都相同

	C++ STL（标准模板库）是一套功能强大的C++ 模板类，提供了通用的模板类和函数，这些模板类和函数可以实现多种流行和常用的算法和数据结构，如向量、链表、队列、栈。 容器是用来管理某一类对象的集合


86. 关键字static、const、extern作用
	static和const的作用在描述时主要从类内和类外两个方面去讲：
	static关键字的作用：
	（1）函数体内static变量的作用范围为该函数体，该变量的内存只被分配一次，因此其值在下次调用时仍维持上次的值；
	（2）在模块内的static全局变量和函数可以被模块内的函数访问，但不能被模块外其它函数访问；
	（3）在类中的static成员变量属于整个类所拥有，对类的所有对象只有一份拷贝；
	（4）在类中的static成员函数属于整个类所拥有，这个函数不接收this指针，因而只能访问类的static成员变量。
	const关键字的作用：
	（1）阻止一个变量被改变
	（2）声明常量指针和指针常量
	（3）const修饰形参，表明它是一个输入参数，在函数内部不能改变其值
	（4）对于类的成员函数，若指定其为const类型，则表明其是一个常函数，不能修改类的成员变量(const成员一般在成员初始化列表处初始化)
	（5）对于类的成员函数，有时候必须指定其返回值为const类型，以使得其返回值不为”左值”。
	extern关键字的作用：
	（1）extern可以置于变量或者函数前，以标示变量或者函数的定义在别的文件中，提示编译器遇到此变量和函数时在其他模块中寻找其定义。
	（2）extern "C"的作用是让 C++ 编译器将extern "C"声明的代码当作 C 语言代码处理，可以避免 C++ 因符号修饰导致代码不能和C语言库中的符号进行链接


87. c++常见容器，vector容器capacity和size区别，如何动态增长 
	为了保证动态添加元素的高效率，因此必须预先为vector和string分配一段空间，这个空间就是capacity。
	而容器中元素的个数就是size()，在容器中，capacity总是大于等于 size
	当出现size > capacity的时候，如果没有空间继续容纳新的元素，不可能将它放到其他位置——因此要保证存储空间要连续。
	因此，容器必须分配新的内存空间（通常比上一次的capacity大一倍），将已有的元素和新的元素拷贝到新的空间中，然后释放旧的存储空间。


88. map容器增删改查，和unorder_map区别，map底层如何实现 
	put(Object key,Object value)  添加一对键值
    get(Object key)  			  根据键返回相关的值，如果不存在指定的键，则返回空值。
	remove(Object key)            删除由指定的键映射的键值对
	containsKey(Object key)       如果存在由指定的键映射的键值对，返回true。
	
	c++中map与unordered_map的区别:
	头文件
	map: #include < map >
	unordered_map: #include < unordered_map >
	内部实现机理
	map内部实现了一个红黑树，该结构具有自动排序的功能，因此map内部的所有元素都是有序的，红黑树的每一个节点都代表着map的一个元素.
	因此，对于map进行的查找，删除，添加等一系列的操作都相当于是对红黑树进行这样的操作，故红黑树的效率决定了map的效率。

	unordered_map: unordered_map内部实现了一个哈希表，因此其元素的排列顺序是杂乱的，无序的
	优缺点以及适用处
	map 
	优点： 
	有序性，这是map结构最大的优点，其元素的有序性在很多应用中都会简化很多的操作,红黑树，内部实现一个红黑书使得map的很多操作在log(n)的时间复杂度下就可以实现，因此效率非常的高
	缺点： 
	空间占用率高，因为map内部实现了红黑树，虽然提高了运行效率，但是因为每一个节点都需要额外保存父节点，孩子节点以及红/黑性质，使得每一个节点都占用大量的空间
	适用处，对于那些有顺序要求的问题，用map会更高效一些
	unordered_map 
	优点： 
	因为内部实现了哈希表，因此其查找速度非常的快
	缺点： 
	哈希表的建立比较耗费时间
	适用处，对于查找问题，unordered_map会更加高效一些，因此遇到查找问题，常会考虑一下用unordered_map


89. c++智能指针 
	auto_ptr, shared_ptr, weak_ptr, unique_ptr

90. emplace_back和push_back区别 
	emplace_back和push_back都是向容器内添加数据.
	对于在容器中添加类的对象时, 相比于push_back,emplace_back可以避免额外类的复制和移动操作.

	
91. 如何实现一个只在堆或者栈上初始化的类
    在C++中，类的对象建立分为两种，一种是静态建立，如A a；另一种是动态建立，如A* ptr=new A；这两种方式是有区别的
    静态建立一个类对象，是由编译器为对象在栈空间中分配内存，是通过直接移动栈顶指针，挪出适当的空间，然后在这片内存空间上调用构造函数形成一个栈对象，使用这种方法，直接调用类的构造函数。
    动态建立类对象，是使用new运算符将对象建立在堆空间中。这个过程分为两步，第一步是执行operator new()函数，在堆空间中搜索合适的内存并进行分配；第二步是调用构造函数构造对象，初始化这片内存空间。
	这种方法，间接调用类的构造函数。
		1、只能在堆上生成对象：将析构函数设置为私有。
			原因：C++是静态绑定语言，编译器管理栈上对象的生命周期，编译器在为类对象分配栈空间时，会先检查类的析构函数的访问性。若析构函数不可访问，则不能在栈上创建对象。
		2、只能在栈上生成对象：将 new 和 delete 重载为私有。
			原因：在堆上生成对象，使用new关键词操作，其过程分为两阶段：第一阶段，使用new在堆上寻找可用内存，分配给对象；第二阶段，调用构造函数生成对象。
			将new操作设置为私有，那么第一阶段就无法完成，就不能够再堆上生成对象。
	
				class A {
				public:
					A() {}
					void destory() { delete this; }
				private:
					~A() {};
				};

				class B {
				private:
					void *operator new(size_t t) {}
					void operator delete (void *ptr) {}
				public:
					B() {}
					~B() {}
				};

			    A a; //error
				A* ptr = new A;

				B b;
				B *ptr_1 = new B; //error


92.  c++的单例模式 
	 定义一个单例类，私有化它的构造函数，以防止外界创建单例类的对象；使用类的私有静态指针变量指向类的唯一实例，并用一个公有的静态方法获取该实例。
		//单例模式
		class Singleton {
		private:
			static Singleton* instance;
		private:
			Singleton();
			~Singleton();
			Singleton(const Singleton&);
			Singleton& operator=(const Singleton&);

		public:
			static Singleton* getInstance() {
				if (instance == NULL) {
					instance = new Singleton();
				}
				return instance;
			}
		};

		Singleton* Singleton::instance = NULL;

93. 快速排序
// 在平均的情况下，快排 的时间复杂度是 O(nlog(n))	
void quicksort(vector<int> &v, int left, int right) {
	if (left >= right) {
		return;
	}
	int lower = left;
	int upper = right;
	while (lower < upper) {
		while (lower < upper && v[upper] >= v[lower]) {    //从后向前搜索
			upper--; // 找到第 1 个比基准数小的值，让它与基准值交换
		}
		swap(v[lower], v[upper]);
		while (lower < upper && v[lower] <= v[upper]) {			//从前向后搜索
			lower++; // 找到第 1 个比基准数大的值，让它与基准值交换
		}
		swap(v[lower], v[upper]);
        // 然后继续寻找，直到 i 与 j 相遇时结束，最后基准值所在的位置即 k 的位置，
        // 也就是说 k 左边的值均比 k 上的值小，而 k 右边的值都比 k 上的值大
	}
    	quicksort(v, left, lower - 1);		//左段
		quicksort(v, upper + 1, right);     //右段
}


94. 引用本质上是一个隐式指针，为对象的一个别名，通过操作符 & 来实现。
	C++11又提出了左值引用与右值引用的概念，一般如没有特殊说明，提到引用都是指传统的左值引用。
	这里顺便提一下变量的两个属性：左值和右值 。左值是变量的地址，右值是变量存储的内容。
	变量本质即存储空间的名称，编译后变为对应地址。
	一个C++引用声明后必须被初始化，否则编译不过，初始化之后就相当与一个变量（地址为初始化时所引用变量的地址）。
	由于拥有共同的地址，而且也是同一个类型，所以对其操作就相当于对原对象的操作，用法和普通变量相同。
	与指针最大的区别：指针是一种数据类型，而引用不是。当其用作函数传参时，传递的就是变量的左值即地址。

	函数返回值时会产生一个临时变量作为函数返回值的副本，而返回引用时不会产生值的副本
	C++( 包括 C) 中所有的表达式和变量要么是左值，要么是右值。通俗的左值的定义就是非临时对象，那些可以在多条语句中使用的对象。
	所有的变量都满足这个定义，在多条代码中都可以使用，都是左值。右值是指临时的对象，它们只在当前的语句中有效

	右值引用 (Rvalue Referene) 是 C++ 新标准 (C++11, 11 代表 2011 年 ) 中引入的新特性 , 它实现了转移语义 (Move Sementics) 和精确传递 (Perfect Forwarding)。
	详细：C++11 标准新特性: 右值引用与转移语义，它的主要目的有两个方面：
	消除两个对象交互时不必要的对象拷贝，节省运算存储资源，提高效率；
	能够更简洁明确地定义泛型函数；
	
	右值引用形式：类型 && a= 被引用的对象。与左值的区别在于：右值是临时变量，如函数返回值，且不变。右值引用可以理解为右值的引用，右值初始化后临时变量消失。
	右值引用是用来支持转移语义的。转移语义可以将资源 ( 堆，系统对象等 ) 从一个对象转移到另一个对象，这样能够减少不必要的临时对象的创建、拷贝以及销毁，能够大幅度提高 C++ 应用程序的性能。
	临时对象的维护 ( 创建和销毁 ) 对性能有严重影响。
	转移语义是和拷贝语义相对的，可以类比文件的剪切与拷贝，当我们将文件从一个目录拷贝到另一个目录时，速度比剪切慢很多。
	通过转移语义，临时对象中的资源能够转移其它的对象里。

95. static
(1) 在全局变量前，加上关键字static，该变量就被定义成为一个静态全局变量
		• 静态全局变量不能被其它文件所用； 
		• 其它文件中可以定义相同名字的变量，不会发生冲突；
(2)在局部变量前，加上关键字static，该变量就被定义成为一个静态局部变量
		通常，在函数体内定义了一个变量，每当程序运行到该语句时都会给该局部变量分配栈内存。但随着程序退出函数体，系统就会收回栈内存，局部变量也相应失效。
		但有时候我们需要在两次调用之间对变量的值进行保存。通常的想法是定义一个全局变量来实现。但这样一来，变量已经不再属于函数本身了，不再仅受函数的控制，给程序的维护带来不便。
		静态局部变量正好可以解决这个问题。静态局部变量保存在全局数据区，而不是保存在栈中，每次的值保持到下一次调用，直到下次赋新值。 
		静态局部变量有以下特点：
		• 该变量在全局数据区分配内存； 
		• 静态局部变量在程序执行到该对象的声明处时被首次初始化，即以后的函数调用不再进行初始化； 
		• 静态局部变量一般在声明处初始化，如果没有显式初始化，会被程序自动初始化为0； 
		• 它始终驻留在全局数据区，直到程序运行结束。但其作用域为局部作用域，当定义它的函数或语句块结束时，其作用域随之结束；

(3)在函数的返回类型前加上static关键字,函数即被定义为静态函数。静态函数与普通函数不同，它只能在声明它的文件当中可见，不能被其它文件使用
			定义静态函数的好处： 
		• 静态函数不能被其它文件所用； 
		• 其它文件中可以定义相同名字的函数，不会发生冲突；

（4）在类内数据成员的声明前加上关键字static，该数据成员就是类内的静态数据成员。
			可以看出，静态数据成员有以下特点： 
			• 对于非静态数据成员，每个类对象都有自己的拷贝。而静态数据成员被当作是类的成员。无论这个类的对象被定义了多少个，静态数据成员在程序中也只有一份拷贝，由该类型的所有对象共享访问。也就是说，静态数据成员是该类的所有对象所共有的。对该类的多个对象来说，静态数据成员只分配一次内存，供所有对象共用。所以，静态数据成员的值对每个对象都是一样的，它的值可以更新； 
			• 静态数据成员存储在全局数据区。静态数据成员定义时要分配空间，所以不能在类声明中定义。在Example 5中，语句int Myclass::Sum=0;是定义静态数据成员； 
			• 静态数据成员和普通数据成员一样遵从public,protected,private访问规则； 
			• 因为静态数据成员在全局数据区分配内存，属于本类的所有对象共享，所以，它不属于特定的类对象，在没有产生类对象时其作用域就可见，即在没有产生类的实例时，我们就可以操作它； 
			• 静态数据成员初始化与一般数据成员初始化不同。静态数据成员初始化的格式为：
			＜数据类型＞＜类名＞::＜静态数据成员名＞=＜值＞ 
			• 类的静态数据成员有两种访问形式：
			＜类对象名＞.＜静态数据成员名＞ 或 ＜类类型名＞::＜静态数据成员名＞
			如果静态数据成员的访问权限允许的话（即public的成员），可在程序中，按上述格式来引用静态数据成员 ； 
			• 静态数据成员主要用在各个对象都有相同的某项属性的时候。比如对于一个存款类，每个实例的利息都是相同的。所以，应该把利息设为存款类的静态数据成员。这有两个好处，第一，不管定义多少个存款类对象，利息数据成员都共享分配在全局数据区的内存，所以节省存储空间。第二，一旦利息需要改变时，只要改变一次，则所有存款类对象的利息全改变过来了； 
			• 同全局变量相比，使用静态数据成员有两个优势： 
			1. 静态数据成员没有进入程序的全局名字空间，因此不存在与程序中其它全局名字冲突的可能性； 
			2. 可以实现信息隐藏。静态数据成员可以是private成员，而全局变量不能；

（5）静态数据成员一样，我们也可以创建一个静态成员函数，它为类的全部服务而不是为某一个类的具体对象服务。静态成员函数与静态数据成员一样，都是类的内部实现，属于类定义的一部分。普通的成员函数一般都隐含了一个this指针，this指针指向类的对象本身，因为普通成员函数总是具体的属于某个类的具体对象的。通常情况下，this是缺省的。如函数fn()实际上是this->fn()。但是与普通函数相比，静态成员函数由于不是与任何的对象相联系，因此它不具有this指针。从这个意义上讲，它无法访问属于类对象的非静态数据成员，也无法访问非静态成员函数，它只能调用其余的静态成员函数
					关于静态成员函数，可以总结为以下几点： 
			• 出现在类体外的函数定义不能指定关键字static； 
			• 静态成员之间可以相互访问，包括静态成员函数访问静态数据成员和访问静态成员函数； 
			• 非静态成员函数可以任意地访问静态成员函数和静态数据成员； 
			• 静态成员函数不能访问非静态成员函数和非静态数据成员； 
			• 由于没有this指针的额外开销，因此静态成员函数与类的全局函数相比速度上会有少许的增长； 
			• 调用静态成员函数，可以用成员访问操作符(.)和(->)为一个类的对象或指向类对象的指针调用静态成员函数，也可以直接使用如下格式：
			＜类名＞::＜静态成员函数名＞（＜参数表＞）
			调用类的静态成员函数。



96. new operator：指我们在C++里通常用到的关键字，比如A* a = new A;
	operator new：它是一个操作符，并且可被重载(类似加减乘除的操作符重载)
					
	A* a = new A；
	我们知道这里分为三步：1.分配内存，2.调用A()构造对象，3. 返回分配指针。
	事实上，分配内存这一操作就是由operator new(size_t)来完成的，如果类A重载了operator new，那么将调用A::operator new(size_t )，否则调用全局::operator new(size_t )，后者由C++默认提供。
	因此前面的步骤也就是：
			调用operator new (sizeof(A))
			调用A:A()
			返回指针

	内存池优化
	operator new的另一个大用处就是内存池优化，内存池的一个常见策略就是分配一次性分配一块大的内存作为内存池(buffer或pool)，然后重复利用该内存块，
	每次分配都从内存池中取出，释放则将内存块放回内存池。在我们客户端调用的是new关键字，我们可以改写operator new函数，让它从内存池中取出(当内存池不够时，
	再从系统堆中一次性分配一块大的)，至于构造和析构则在取出的内存上进行，然后再重载operator delete，它将内存块放回内存池。

1.用typedef 定义一个包含10个整型的类型
	注：typedef int NUMBER[10];
	NUMBER 声明为含有10个元素的数组类型。
	NUMBER n;
	n[0] =1;
	n为含有10个元素的数组。

假设你只知道一个数组的数组名（a[]),如何确定这个数组的长度？
int length = sizeof(a)/sizeof(a[0]);


1. 静态函数
	在函数返回类型前加static，函数就定义为静态函数。函数的定义和声明在默认情况下都是extern的，但静态函数只是在声明他的文件当中可见，不能被其他文件所用。
	函数的实现使用static修饰，那么这个函数只可在本cpp内使用，不会同其他cpp中的同名函数引起冲突；
	warning：不要再头文件中声明static的全局函数，不要在cpp内声明非static的全局函数，如果你要在多个cpp中复用该函数，就把它的声明提到头文件里去，否则cpp内部声明需加上static修饰；

2.说一下C++中static关键字的作用
	对于函数定义和代码块之外的变量声明，static修改标识符的链接属性，由默认的external变为internal，作用域和存储类型不改变，这些符号只能在声明它们的源文件中访问。
	对于代码块内部的变量声明，static修改标识符的存储类型，由自动变量改为静态变量，作用域和链接属性不变。这种变量在程序执行之前就创建，在程序执行的整个周期都存在。
	对于被static修饰的普通函数，其只能在定义它的源文件中使用，不能在其他源文件中被引用
	对于被static修饰的类成员变量和成员函数，它们是属于类的，而不是某个对象，所有对象共享一个静态成员。静态成员通过<类名>::<静态成员>来使用。

3.说一说c++中四种cast转换
		C++中四种类型转换是：static_cast, dynamic_cast, const_cast, reinterpret_cast
		1、const_cast
		用于将const变量转为非const
		2、static_cast
		用于各种隐式转换，比如非const转const，void*转指针等, static_cast能用于多态向上转化，如果向下转能成功但是不安全，结果未知；
		3、dynamic_cast
		用于动态类型转换。只能用于含有虚函数的类，用于类层次间的向上和向下转化。只能转指针或引用。向下转化时，如果是非法的对于指针返回NULL，对于引用抛异常。要深入了解内部转换的原理。
		向上转换：指的是子类向基类的转换
		向下转换：指的是基类向子类的转换
		它通过判断在执行到该语句的时候变量的运行时类型和要转换的类型是否相同来判断是否能够进行向下转换。
		4、reinterpret_cast
		几乎什么都可以转，比如将int转指针，可能会出问题，尽量少用；
		
		静态类型在编译的时候就已经确定,他是变量的申明类型或者是表达式生成的类型,而动态类型是变量或者表达式表示的内存中的对象的类型,动态类型要到运行的时候才能确定.
		基类的指针或者引用的动态类型可能和它的静态类型不一致.

4.智能指针主要用于管理在堆上分配的内存，它将普通的指针封装为一个栈对象。
	当栈对象的生存周期结束后，会在析构函数中释放掉申请的内存，从而防止内存泄漏。
	C++ 11中最常用的智能指针类型为shared_ptr,它采用引用计数的方法，记录当前内存资源被多少个智能指针引用。该引用计数的内存在堆上分配。当新增一个时引用计数加1，当过期时引用计数减一。
	只有引用计数为0时，智能指针才会自动释放引用的内存资源。对shared_ptr进行初始化时不能将一个普通指针直接赋值给智能指针，因为一个是指针，一个是类。
	可以通过make_shared函数或者通过构造函数传入普通指针。并可以通过get函数获得普通指针。


5. 请你回答一下为什么析构函数必须是虚函数？为什么C++默认的析构函数不是虚函数 考点:虚函数 析构函数
	将可能会被继承的父类的析构函数设置为虚函数，可以保证当我们new一个子类，然后使用基类指针指向该子类对象，释放基类指针时可以释放掉子类的空间，防止内存泄漏。
	C++默认的析构函数不是虚函数是因为虚函数需要额外的虚函数表和虚表指针，占用额外的内存。
	而对于不会被继承的类来说，其析构函数如果是虚函数，就会浪费内存。因此C++默认的析构函数不是虚函数，而是只有当需要当作父类时，设置为虚函数。

	
5. 函数指针是指向函数的指针变量。
	函数指针本身首先是一个指针变量，该指针变量指向一个具体的函数。这正如用指针变量可指向整型变量、字符型、数组一样，这里是指向函数
	用途：调用函数和做函数的参数，比如回调函数

6.请你说说C语言参数压栈顺序？
	参考回答：从右到左

7.请你说说C++如何处理返回值？
	参考回答：生成一个临时变量，把它的引用作为函数参数传入函数内

8.请你回答一下静态函数和虚函数的区别
参考回答：静态函数在编译的时候就已经确定运行时机，虚函数在运行的时候动态绑定。虚函数因为用了虚函数表机制，调用的时候会增加一次内存开销


9. 请你来说一下map和set有什么区别，分别又是怎么实现的？
map和set都是C++的关联容器，其底层实现都是红黑树（RB-Tree）。由于 map 和set所开放的各种操作接口，RB-tree 也都提供了，所以几乎所有的 map 和set的操作行为，都只是转调 RB-tree 的操作行为。
map和set区别在于:
（1）map中的元素是key-value（关键字—值）对：关键字起到索引的作用，值则表示与索引相关联的数据；Set与之相对就是关键字的简单集合，set中每个元素只包含一个关键字。
（2）set的迭代器是const的，不允许修改元素的值；map允许修改value，但不允许修改key。其原因是因为map和set是根据关键字排序来保证其有序性的，如果允许修改key的话，那么首先需要删除该键，然后调节平衡，再插入修改后的键值，调节平衡，
     如此一来，严重破坏了map和set的结构，导致iterator失效，不知道应该指向改变前的位置，还是指向改变后的位置。所以STL中将set的迭代器设置成const，不允许修改迭代器的值；而map的迭代器则不允许修改key值，允许修改value值。
		set适用场景：有序不重复集合
（3）map支持下标操作，set不支持下标操作。map可以用key做下标，map的下标运算符[ ]将关键码作为下标去执行查找，如果关键码不存在，则插入一个具有该关键码和mapped_type类型默认值的元素至map中，
    因此下标运算符[ ]在map应用中需要慎用，const_map不能用，只希望确定某一个关键值是否存在而不希望插入元素时也不应该使用，mapped_type类型没有默认值也不应该使用。如果find能解决需要，尽可能用find。
	map适用场景：有序键值对不重复映射


10. 请你来说一说STL迭代器删除元素
    这个主要考察的是迭代器失效的问题。
	1.对于序列容器vector,deque来说，使用erase(itertor)后，后边的每个元素的迭代器都会失效，但是后边每个元素都会往前移动一个位置，但是erase会返回下一个有效的迭代器；
	2.对于关联容器map set来说，使用了erase(iterator)后，当前元素的迭代器失效，但是其结构是红黑树，删除当前元素的，不会影响到下一个元素的迭代器，所以在调用erase之前，记录下一个元素的迭代器即可。
	3.对于list来说，它使用了不连续分配的内存，并且它的erase方法也会返回下一个有效的iterator，因此上面两种正确的方法都可以使用。


11. 请你说一说STL中MAP数据存放形式
    map是红黑树。unordered map底层结构是哈希表

12. 
vector拥有一段连续的内存空间，因此支持随机访问，如果需要高效的随即访问，而不在乎插入和删除的效率，使用vector。
list拥有一段不连续的内存空间，如果需要高效的插入和删除，而不关心随机访问，则应使用list


13. 请你来说一下STL中迭代器的作用，有指针为何还要迭代器
	迭代器不是指针，是类模板，表现的像指针。他只是模拟了指针的一些功能，通过重载了指针的一些操作符，->、*、++、--等。
	迭代器封装了指针，是一个“可遍历STL（ Standard Template Library）容器内全部或部分元素”的对象， 本质是封装了原生指针，是指针概念的一种提升（lift），
	提供了比指针更高级的行为，相当于一种智能指针，他可以根据不同类型的数据结构来实现不同的++，--等操作。

	迭代器返回的是对象引用而不是对象的值，所以cout只能输出迭代器使用*取值后的值而不能直接输出其自身。
	Iterator类的访问方式就是把不同集合类的访问逻辑抽象出来，使得不用暴露集合内部的结构而达到循环遍历集合的效果




15.请你回答一下什么是右值引用，跟左值又有什么区别？
	参考回答：
	右值引用是C++11中引入的新特性 , 它实现了转移语义和精确传递。它的主要目的有两个方面：
	1. 消除两个对象交互时不必要的对象拷贝，节省运算存储资源，提高效率。
	2. 能够更简洁明确地定义泛型函数。

	左值和右值的概念：
	左值：能对表达式取地址、或具名对象/变量。一般指表达式结束后依然存在的持久对象
	右值：不能对表达式取地址，或匿名对象。一般指表达式结束就不再存在的临时对象。

	右值引用和左值引用的区别：
	1. 左值可以寻址，而右值不可以。
	2. 左值可以被赋值，右值不可以被赋值，可以用来给左值赋值。
	3. 左值可变,右值不可变（仅对基础类型适用，用户自定义类型右值引用可以通过成员函数改变）。




17. 是大端小端以及如何判断大端小端
	大端是指低字节存储在高地址；小端存储是指低字节存储在低地址。

18. 一下静态变量什么时候初始化
   静态变量存储在虚拟地址空间的数据段和bss段，C语言中其在代码执行之前初始化，属于编译期初始化。
   而C++中由于引入对象，对象生成必须调用构造函数，因此C++规定全局或局部静态对象当且仅当对象首次用到时进行构造

19.死循环+来连接时新建线程的方法效率有点低，怎么改进？
	提前创建好一个线程池，用生产者消费者模型，创建一个任务队列，队列作为临界资源，有了新连接，就挂在到任务队列上，队列为空所有线程睡眠。
	改进死循环：使用select epoll这样的技术


			
23. 请你说一下源码到可执行文件的过程
	
	1）预编译
	主要处理源代码文件中的以“#”开头的预编译指令。处理规则见下
	1、删除所有的#define，展开所有的宏定义。

				2、处理所有的条件预编译指令，如“#if”、“#endif”、“#ifdef”、“#elif”和“#else”。

				3、处理“#include”预编译指令，将文件内容替换到它的位置，这个过程是递归进行的，文件中包含其他文件。

				4、删除所有的注释，“//”和“/**/”。

				5、保留所有的#pragma 编译器指令，编译器需要用到他们，如：#pragma once 是为了防止有文件被重复引用。

				6、添加行号和文件标识，便于编译时编译器产生调试用的行号信息，和编译时产生编译错误或警告是能够显示行号。

				2）编译

				把预编译之后生成的xxx.i或xxx.ii文件，进行一系列词法分析、语法分析、语义分析及优化后，生成相应的汇编代码文件。

				1、词法分析：利用类似于“有限状态机”的算法，将源代码程序输入到扫描机中，将其中的字符序列分割成一系列的记号。

				2、语法分析：语法分析器对由扫描器产生的记号，进行语法分析，产生语法树。由语法分析器输出的语法树是一种以表达式为节点的树。

				3、语义分析：语法分析器只是完成了对表达式语法层面的分析，语义分析器则对表达式是否有意义进行判断，其分析的语义是静态语义——在编译期能分期的语义，相对应的动态语义是在运行期才能确定的语义。

				4、优化：源代码级别的一个优化过程。

				5、目标代码生成：由代码生成器将中间代码转换成目标机器代码，生成一系列的代码序列——汇编语言表示。

				6、目标代码优化：目标代码优化器对上述的目标机器代码进行优化：寻找合适的寻址方式、使用位移来替代乘法运算、删除多余的指令等。

				3）汇编

				将汇编代码转变成机器可以执行的指令(机器码文件)。 汇编器的汇编过程相对于编译器来说更简单，没有复杂的语法，也没有语义，更不需要做指令优化，只是根据汇编指令和机器指令的对照表一一翻译过来，汇编过程有汇编器as完成。经汇编之后，产生目标文件(与可执行文件格式几乎一样)xxx.o(Windows下)、xxx.obj(Linux下)。

				4）链接

				将不同的源文件产生的目标文件进行链接，从而形成一个可以执行的程序。链接分为静态链接和动态链接：

				1、静态链接：

				函数和数据被编译进一个二进制文件。在使用静态库的情况下，在编译链接可执行文件时，链接器从库中复制这些函数和数据并把它们和应用程序的其它模块组合起来创建最终的可执行文件。

				空间浪费：因为每个可执行程序中对所有需要的目标文件都要有一份副本，所以如果多个程序对同一个目标文件都有依赖，会出现同一个目标文件都在内存存在多个副本；

				更新困难：每当库函数的代码修改了，这个时候就需要重新进行编译链接形成可执行程序。

				运行速度快：但是静态链接的优点就是，在可执行程序中已经具备了所有执行程序所需要的任何东西，在执行的时候运行速度快。

				2、动态链接：

				动态链接的基本思想是把程序按照模块拆分成各个相对独立部分，在程序运行时才将它们链接在一起形成一个完整的程序，而不是像静态链接一样把所有程序模块都链接成一个单独的可执行文件。

				共享库：就是即使需要每个程序都依赖同一个库，但是该库不会像静态链接那样在内存中存在多分，副本，而是这多个程序在执行时共享同一份副本；

				更新方便：更新时只需要替换原来的目标文件，而无需将所有的程序再重新链接一遍。当程序下一次运行时，新版本的目标文件会被自动加载到内存并且链接起来，程序就完成了升级的目标。

				性能损耗：因为把链接推迟到了程序运行时，所以每次执行程序都需要进行链接，所以性能会有一定损失			
							


24.请问GDB调试用过吗，什么是条件断点
	参考回答：
	1、GDB调试
	GDB 是自由软件基金会（Free Software Foundation）的软件工具之一。它的作用是协助程序员找到代码中的错误。
	如果没有GDB的帮助，程序员要想跟踪代码的执行流程，唯一的办法就是添加大量的语句来产生特定的输出。但这一手段本身就可能会引入新的错误，从而也就无法对那些导致程序崩溃的错误代码进行分析。
	GDB的出现减轻了开发人员的负担，他们可以在程序运行的时候单步跟踪自己的代码，或者通过断点暂时中止程序的执行。此外，他们还能够随时察看变量和内存的当前状态，并监视关键的数据结构是如何影响代码运行的。

	2、条件断点
	条件断点是当满足条件就中断程序运行，命令：break line-or-function if expr。
	例如：(gdb)break 666 if testsize==100							
			
			
25. 请你回答一下操作系统为什么要分内核态和用户态
为了安全性。在cpu的一些指令中，有的指令如果用错，将会导致整个系统崩溃。分了内核态和用户态后，当用户需要操作这些指令时候，内核为其提供了API，可以通过系统调用陷入内核，让内核去执行这些操作			


26. 请你说一下多线程的同步，锁的机制
	同步的时候用一个互斥量，在访问共享资源前对互斥量进行加锁，在访问完成后释放互斥量上的锁。
	对互斥量进行加锁以后，任何其他试图再次对互斥量加锁的线程将会被阻塞直到当前线程释放该互斥锁。
	如果释放互斥锁时有多个线程阻塞，所有在该互斥锁上的阻塞线程都会变成可运行状态，第一个变为运行状态的线程可以对互斥量加锁，其他线程将会看到互斥锁依然被锁住，只能回去再次等待它重新变为可用。在这种方式下，每次只有一个线程可以向前执行


27. 你说一说线程间的同步方式，最好说出具体的系统调用
	信号量
	信号量是一种特殊的变量，可用于线程同步。它只取自然数值，并且只支持两种操作：
	P(SV):如果信号量SV大于0，将它减一；如果SV值为0，则挂起该线程。
	V(SV)：如果有其他进程因为等待SV而挂起，则唤醒，然后将SV+1；否则直接将SV+1。
	其系统调用为：
	sem_wait（sem_t *sem）：以原子操作的方式将信号量减1，如果信号量值为0，则sem_wait将被阻塞，直到这个信号量具有非0值。
	sem_post（sem_t *sem)：以原子操作将信号量值+1。当信号量大于0时，其他正在调用sem_wait等待信号量的线程将被唤醒。

	互斥量
	互斥量又称互斥锁，主要用于线程互斥，不能保证按序访问，可以和条件锁一起实现同步。当进入临界区时，需要获得互斥锁并且加锁；当离开临界区时，需要对互斥锁解锁，以唤醒其他等待该互斥锁的线程。其主要的系统调用如下：
	pthread_mutex_init:初始化互斥锁
	pthread_mutex_destroy：销毁互斥锁
	pthread_mutex_lock：以原子操作的方式给一个互斥锁加锁，如果目标互斥锁已经被上锁，pthread_mutex_lock调用将阻塞，直到该互斥锁的占有者将其解锁。
	pthread_mutex_unlock:以一个原子操作的方式给一个互斥锁解锁。

	条件变量
	条件变量，又称条件锁，用于在线程之间同步共享数据的值。条件变量提供一种线程间通信机制：当某个共享数据达到某个值时，唤醒等待这个共享数据的一个/多个线程。
	即，当某个共享变量等于某个值时，调用 signal/broadcast。此时操作共享变量时需要加锁。其主要的系统调用如下：
	pthread_cond_init:初始化条件变量
	pthread_cond_destroy：销毁条件变量
	pthread_cond_signal：唤醒一个等待目标条件变量的线程。哪个线程被唤醒取决于调度策略和优先级。
	pthread_cond_wait：等待目标条件变量。需要一个加锁的互斥锁确保操作的原子性。该函数中在进入wait状态前首先进行解锁，然后接收到信号后会再加锁，保证该线程对共享资源正确访问。


28. 请问你用过哪些设计模式，介绍一下单例模式的多线程安全问题

	常见的设计模式如下：
	单例模式：
	单例模式主要解决一个全局使用的类频繁的创建和销毁的问题。单例模式下可以确保某一个类只有一个实例，而且自行实例化并向整个系统提供这个实例。
	单例模式有三个要素：一是某个类只能有一个实例；二是它必须自行创建这个实例；三是它必须自行向整个系统提供这个实例。

	将该类的构造方法定义为私有方法，这样其他处的代码就无法通过调用该类的构造方法来实例化该类的对象，只有通过该类提供的静态方法来得到该类的唯一实例；
	在该类内提供一个静态方法，当我们调用这个方法时，如果类持有的引用不为空就返回这个引用，如果类保持的引用为空就创建该类的实例并将实例的引用赋予该类保持的引用。

	在单例模式的实现中，如果不采取任何措施，在多线程下是不安全的，可能会同时创建多个实例。因此，为了保证单例模式在多线程下的线程安全，一般采用下面几种方式实现单例模式：
	1)饿汉式：基于class loader机制避免多线程的同步问题，不过，instance在类装载时就实例化，可能会产生垃圾对象
	2)懒汉式：通过双重锁机制实现线程安全,  使用锁机制，防止多次访问,可以这样，第一次判断为空不加锁，若为空，再进行加锁判断是否为空，若为空则生成对象


	工厂模式：工厂模式主要解决接口选择的问题。该模式下定义一个创建对象的接口，让其子类自己决定实例化哪一个工厂类，使其创建过程延迟到子类进行。

	观察者模式：定义对象间的一种一对多的依赖关系，当一个对象的状态发生改变时，所有依赖于它的对象都得到通知并被自动更新

	装饰器模式：对已经存在的某些类进行装饰，以此来扩展一些功能，从而动态的为一个对象增加新的功能。装饰器模式是一种用于代替继承的技术，无需通过继承增加子类就能扩展对象的新功能。使用对象的关联关系代替继承关系，更加灵活，同时避免类型体系的快速膨胀
		优点：装饰类和被装饰类可以独立发展，不会相互耦合，装饰模式是继承的一个替代模式，装饰模式可以动态扩展一个实现类的功能。
		缺点：多层装饰比较复杂。  使用场景：1、扩展一个类的功能。 2、动态增加功能，动态撤销


	
29.


double x[5]={2.0, 4.0, 6.0, 8.0, 10.0};

		   
31.
int a[][2] = { 0 };
int b[][2] = { { 1, 2 }, { 3, 4 } };
int c[][2] = { { 1, 2,}, { 3, 4 }, {0} };
都是可以的。
但是int array[][2];不行
二维数组赋初值方法（c程序设计第三版138页）
（4）如果对全部元素都赋初值，则定义数组时第一维可以忽略，但是第二维必须存在
         同时：在定义的时候也可以对部分元素赋初值而忽略第一维的长度，但应该分行赋初值。
可见：可以忽略第一维的长度，但是是有条件的：要么你把全部元素都写出来，或者你分行写出元素（可以不全），但是不可以不赋值



32.
scanf("m=%dn=%dp=%d",&m,&n,&p);
Inputs:
m=123n=456p=789
scanf函数完全就是字符串匹配而已啦

33.
char *p[10] 是指针数组,数组里存放了10个指针,在64位系统下指针占8个字节,所以sizeof(p) = 10 * 8 = 80.
char (*p1)[10]是数组指针,p1是一个指向存放10个char类型的数组的指针,所以sizeof(p1) = 8.


34. 
do-while循环 ：在判断while条件前先执行一次do循环
static变量 ：程序再次调用时static变量的值不会重新初始化，而是在上一次退出时的基础上继续执行。


35.
非常量引用的初始值必须为左值

要理解这个先得理解左值和右值的概念
一个区分左值与右值的便捷方法是：看能不能对表达式取地址，如果能，则为左值，否则为右值。
本题举例：
执行f1(0),实参0要传成A对象，那么执行
A &a1 = 0;   //这是不行的。
执行f2(0),实参0要传成A对象，那么执行 
const A &a2 = 0;//这是可行的。

左值和右值都是针对表达式而言的，左值是指表达式结束后依然存在的持久对象，右值是指表达式结束时就不再存在的临时对象。
在标准C++语言中，临时量（术语为右值，因其出现在赋值表达式的右边）可以被传给函数，但只能被接受为const &类型。

函数形式参数是临时量，是右值。所以只能被接受为const &类型 。故A错。



36.
那应该是在定义数组时[ ]里只能是整型常量表达式，这里是引用数组元素，例如for循环里arr[i]经常出现，i就是整型变量


37.
p = &x;  表示的是，对x取地址，赋值给指针p，那么p 将指向 x 的那块内存空间，但是 x  是形式参数(也有人说是方法参数，都可以)，函数调用完了之后，内存就释放了，所以再返回 *p（即取出那块内存空间的值），已经找不到了。所以错误。
*p = x；  表示的是 将 x 的值赋值给 P 所指向的空间，而p之前并没有指向任何地方，这个操作将是非法的。
*p = new int(x)；   这个操作同 A 的结果一样。
p = new int(x);  new int(x) 新申请空间，调用完后不释放空间，所以将地址赋值给p 则p 指向了这段新申请内存空间，所以当做  *p 返回时，即取出p所执行空间的值，所以会输出5


38.
A： a+=(a++)    先计算a++ ，因为a为后++,a左边是左值不会报错 ;
B： a+=(++a)    先计算++a,因为a为前++, a左边是左值不会报错 ;
C:：(a++) += a  这个是错误的。因为左值只能是变量,不能是表达式，(a++)是后++, 所以a不会先计算a++,是表达式，。所以会报错。
D：(++a) +=(a++) 先计算++a,然后再去计算a +=(a++) ,所以左边也是左值 ; 




39.
cin遇到空格 结束输入，

40.
这个考点常考
“hello”存在内存常量区
char *p1 = "hello";char *p2= "hello";
那么p1==p2
但是&p1!=&p2
"hello"整个是地址，只不过cout会把它当字符串输出，这与cout输出p是一样的道理，
p也是地址，但是cout知道他是字符串的首地址，所以认为你想输出的是字符串
cout <<hex<< (int)p <<endl<< (int)("hello") << endl;
这样写，就知道p和"hello"一样，都是地址，而且它们的值相同。
另外一点，这个p指向的字符串不能修改，理由已经说了，这个字符串存在常量区
如果修改会报错。


41.
短路原则，如果是 || ，前面真后面就不执行，如果是 && 前面为真后面才执行	   
“对于逻辑表达式：a++ && b++，设a的值为0，则求解表达式的值后，b的值会发生改变”
a的值为0，又因为a++是先用a参与表达式运算，再执行a=a+1,所以表达式的值为假，后面的也不会执行	   


42.
定义一个新变量，把x赋值给它   			 int rx = x; 
定义一个int变量，把x的地址赋给它   		int rx = &x; 
定义一个int指针变量，把x的地址赋给它 	int *rx = &x; 
定义一个引用变量，即把rx定义为x的别名    int &rx = x;


43.
ios类派生istream类和ostream类，istream类和ostream类共同派生出iostream类，cin是istream类对象，cout是ostream类对象;cin和cout可以说是来自iostream类的
cin是istream的类对象
而istream的常见成员函数有：istream::getline() 函数， istream::ignore() 函数， istream::get() 函数等

44.
C语言中有数字三种表示：十进制、八进制(0开头)、十六进制(0x开头)


45.
如果大写字母变成小写字母时，就加32

46.
111111B第一位为符号位,则-2^5=-32；它的范围是从-2^5----2^5-1
如果是无符号数，，它6位数都参与预算，，111111代表的0到正63，如果是有符号数，，最高位当成符号位，不参与运算，，从0 00000到0 11111是0到31，而从1 00001 到1 11111为负1到负31，中间有一个1 00000本意表示负零，
但是负零和正零都表示零，重复了。所以计算机规定把1 00000表示-32

47.
sizeof对数组就是数组长度*数据类型长度
sizeof对指针就是int型长度
sizeof对数据类型自然是数据类型长度
sizeof对结构体需要考虑结构的字节对齐


48.
a代表数组的第一个元素  a = &a[0]，而&a+1就意思在整个大数组基础上，地址加“1“

49. c++在c的基础上加入了std,c++风格的字符串 string str1 = "Hello"; c风格的字符串 char str1[11] = "Hello";

50. 二叉搜索树或者是一棵空树，或者是具有下列性质的二叉树:
		若左子树不空，则左子树上所有结点的值均小于它的根结点的值
		若右子树不空，则右子树上所有结点的值均大于或等于它的根结点的值


51.
begin() returns an iterator that can be used to iterate through the collection, while front() just returns a reference to the first element of the collection.
front() returns a reference to the first element, begin() returns an iterator to it


52.头文件中的ifndef/define/endif有什么作用？
答：这是C++预编译头文件保护符，保证即使文件被多次包含，头文件也只定义一次



52．关于sizeof小结的。
答：sizeof计算的是在栈中分配的内存大小。
（1） sizeof不计算static变量占得内存；
（2） 32位系统的指针的大小是4个字节，64位系统的指针是8字节，而不用管指针类型；
（3） char型占1个字节，int占4个字节，short int占2个字节
long int占4个字节，float占4字节，double占8字节，string占4字节
一个空类占1个字节，单一继承的空类占1个字节，虚继承涉及到虚指针所以占4个字节
（4） 数组的长度：
若指定了数组长度，则不看元素个数，总字节数=数组长度*sizeof（元素类型）
若没有指定长度，则按实际元素个数类确定
Ps：若是字符数组，则应考虑末尾的空字符。
（5） 结构体对象的长度
在默认情况下，为方便对结构体内元素的访问和管理，当结构体内元素长度小于处理器位数的时候，便以结构体内最长的数据元素的长度为对齐单位，即为其整数倍。若结构体内元素长度大于处理器位数则以处理器位数为单位对齐。
（6） unsigned影响的只是最高位的意义，数据长度不会改变，所以sizeof（unsigned int）=4
（7） 自定义类型的sizeof取值等于它的类型原型取sizeof
（8） 对函数使用sizeof，在编译阶段会被函数的返回值的类型代替
（9） sizeof后如果是类型名则必须加括号，如果是变量名可以不加括号，这是因为sizeof是运算符
（10） 当使用结构类型或者变量时，sizeof返回实际的大小。当使用静态数组时返回数组的全部大小，sizeof不能返回动态数组或者外部数组的尺寸


53. C++中有malloc/free，为什么还有new/delete？
答：malloc/free是C/C++标准库函数，new/delete是C++运算符。他们都可以用于动态申请和释放内存。
对于内置类型数据而言，二者没有多大区别。malloc申请内存的时候要制定分配内存的字节数，而且不会做初始化；new申请的时候有默认的初始化，同时可以指定初始化；
对于类类型的对象而言，用malloc/free无法满足要求的。对象在创建的时候要自动执行构造函数，消亡之前要调用析构函数。由于malloc/free是库函数而不是运算符，不在编译器控制之内，不能把执行构造函数和析构函数的任务强加给它，因此，C++还需要new/delete。



54.继承层次中，为什么基类析构函数是虚函数？
答：编译器总是根据类型来调用类成员函数。但是一个派生类的指针可以安全地转化为一个基类的指针。这样删除一个基类的指针的时候，
C++不管这个指针指向一个基类对象还是一个派生类的对象，调用的都是基类的析构函数而不是派生类的。
如果你依赖于派生类的析构函数的代码来释放资源，而没有重载析构函数，那么会有资源泄漏


55. 重载和覆盖有什么区别？
答：虚函数是基类希望派生类重新定义的函数，派生类重新定义基类虚函数的做法叫做覆盖；
重载就在允许在相同作用域中存在多个同名的函数，这些函数的参数表不同。重载的概念不属于面向对象编程，编译器根据函数不同的形参表对同名函数的名称做修饰，然后这些同名函数就成了不同的函数。
重载的确定是在编译时确定，是静态的；虚函数则是在运行时动态确定

final的作用：修饰类或成员函数

修饰类时： 表示本类禁止被继承；
修饰成员函数：
    virtual成员函数：表示不允许子类重写覆盖，但可以重写隐藏
    非virtual成员函数：表示不允许子类重写隐藏；
override:用于标示虚函数，明确说明这是重写覆盖父类的同名函数，避免造成重写隐藏的情况；



56. 
// 如今的c++已经是一个多重泛型变成语言。支持过程化，面向对象，函数式，泛型和元编程的组合。这种强大使得c++无可匹敌，却也带来了一些问题。所有“合适的”规则看上去都有例外。我们怎样理解这样一门语言？

// c++ 是以c为基础的:区块(blocks), 语句(statements),预处理(pre-processor),内置数据类型(build-in data types),数组(array),指针(pointers)
// objected-oriented C++: class包括构造函数,析构函数,封装(encapsulation),继承(inheritance),多态(ploymorphism),虚函数(动态绑定)
// template c++ : 泛型编程和模板
// STL: template的函数库, 容器,迭代器,算法,函数对象

// 最容易的方法是不要将其看成单一的一门语言而是将其看成是一个有相关性的语言的联邦。在一个特定的子语言中，一些规则就比较简单，明确并且容易记忆。
// 当你从一个子语言切换到另外一个子语言时，这些规则可能会改变。为了更好的理解c++,你必须识别主要的子语言，幸运的是，只有四种子语言:
// c++以c语言为基础。块，声明，预处理，内建类型，数组，指针等等。都来自于c语言。在许多情况下，c++只不过提供了一些比c高级的解法，但是当你发现你自己正在使用c++中的c语言部分时，高效编程的规则反映出c语言更多的局限性：没有模板，没有异常处理，没有重载等等。
// 面向对象c++.c++这部分就是带类的c语言，主要包括：类（包括析构函数和构造函数），封装 ，继承，多态，虚函数（动态绑定）等等。
// 模板c++.这是c++的泛型编程部分，也是大多数程序员在经验方面所欠缺的，关于模板编程的设计遍及整c++编程，一些好的编程规则中包含只适用于模板的条款。事实上，模板编程如此强大，它带来了一个新的编程范型，模板元编程(TPM).
// STL.STL是一个模板库。它将容器，迭代器，算法和函数对象优雅的整合到一起，模板和库也可以用其他的方法构建出来。使用模板库有自己特殊的方式，当你在使用STL时，你必须遵循它的约定。
// 将这四种子语言记在心里，在不同的子语言之间进行切换时，高效编程可能需要变换策略，譬如，c语言中对于内建类型，按值传递比按引用传递要高效。在c++中，对于类对象来说，因为用户自定义的构造函数和析构函数的存在，按引用传递比按值传递要高效，模板c++中也是如此。但是在STL中，迭代器和函数对象是模仿的C语言中的指针，因此按值传递会比较高效。

// 因此c++不是统一标准的语言。它是一个语言联邦，每个子语言都有自己的约定



57.
// Item 6 如果你不想使用编译器自动生成的函数，你需要明确拒绝
// 阻止对象拷贝方法一-将拷贝构造函数和赋值运算符声明为private,并且不去实现它们



58. Item 12 拷贝对象的所有部分
// 在设计良好的面向对象系统中，会将对象的内部进行封装，只有两个函数可以拷贝对象：拷贝构造函数和拷贝赋值运算符。我们把这两个函数统一叫做拷贝函数。
// 从Item5中，我们得知，如果需要的话编译器会为你生成这两个拷贝函数，并且编译器生成的版本能够精确的做到你想做的：它们拷贝了对象的所有数据。
// 当你实现一个拷贝函数的时候，确保（1）拷贝所有本地的数据成员。（2）同时调用所有基类的合适的拷贝函数。

59.
通过对象来管理需要手动释放的资源:
我们已经说出了这个条款一半的内容：通过将资源放入对象中，我们可以依赖c++的析构函数自动调用机制来确保资源被释放

使用auto_ptr来管理资源

不要将auto_ptr和shared_ptr用于动态分配数组


60.在资源管理类中提供对原生(raw)资源的访问
std::shared_ptr<Investment> pInv(createInvestment()); // from Item 13
int days = daysHeld(pInv.get()); // fine, passes the raw pointer



61.

//  Item 17 使用单独语句将new出来的对象放入智能指针
 // 在智能指针中存储new出来的对象时要用单独的语句，不然抛出异常的时候会发生微妙的资源泄漏


 62.
 //  Item 20 优先使用按const-引用传递（by-reference-to-const）而不是按值传递(by value)

 63.// Item 27 尽量少使用转型（casting）
// C++风格的cast
// C++同样提供四种新的casts形式（C++风格的casts:
//  const_cast<T>(expression)
//  dynamic_cast<T>(expression)
//  reinterpret_cast<T>(expression)
//  static_cast<T>(expression)

// 每种方法都有独特的用途：
// Const_cast是用来去除对象的常量性的（constness）。在四个C++风格的cast中，const_cast是唯一能做到这一点的。
// Dynamic_cast主要用来执行“安全的向下转型”，也就是决定一个特定类型的对象是否在一个继承体系中。这也是唯一一个不能用旧式风格语法来实现的cast。
// 它也是唯一一个可能会出现巨大的运行时开销的cast。（稍后会详细讲解）
// Reinterpret_cast被用来做低级的casts，结果可能依赖于编译器，也就是代码不能被移植，例如，将一个指针转换成int。这种casts除了用在低级代码中，其他地方很少见。本书中只出现过一次，就是在讨论如何为原生内存（raw memory）实现一个调试分配器(Item 50)。
// Static_cast能被用来做强制的显示类型转换（比如，non-const对象转换成const对象(Item 3)，int转换成double等等。）它同样能够用来对这些转换进行反转（比如，void*转换成具体类型指针，指向base的指针转换成指向派生类的指针），但是不能从const转换成非const对象（只有const_cast能这么做）。



64.// Item 32 确保public继承建立“is-a”模型
// 1. 何为public继承的”is-a”关系
// 在C++面向对象准则中最重要的准则是：public继承意味着“is-a”。记住这个准则。

// 如果你实现一个类D(derived) public 继承自类B(base),你在告诉c++编译器（也在告诉代码阅读者），每个类型D的对象也是一个类型B的对象，反过来说是不对的。你正在诉说B比D表示了一个更为一般的概念，
// 而D比B表现了一个更为特殊的概念。你在主张：任何可以使用类型B的地方，也能使用类型D，因为每个类型D的对象都是类型B的对象；反过来却不对，也就是可以使用类型D的地方却不可以使用类型B：D是B，B不是D。


65.  
// Private继承意味着“is-implemented-in-terms-of”
  

66. 
// 迭代器 .end() 是最后一个元素的后一位
迭代器不能++ 或者--,自加,自减
  --e.end() 不合法

67.
减少临时对象:
    使用 const &,不要值传递
    使用 ++i 
    在函数里面定义局部变量,用于返回,避免return产生临时变量


68.当在派生类中定义一个函数和基类里面函数同名是,如果不想隐藏掉基类里面的函数,需要使用 using declaration
                                                                        using Based::f


69. private 继承: has-a , is implemented in terms of
   public 继承, is-a


70. 指针与引用的区别
// 在任何情况下都不能使用指向空值的引用,在 C++里,引用应被初始化
// 不存在指向空值的引用这个事实意味着使用引用的代码效率比使用指针的要高。因为在使用引用之前不需要测试它的合法性
// 指针与引用的另一个重要的不同是指针可以被重新赋值以指向另一个不同的对象。但是引用则总是指向在初始化时被指定的对象,以后不能改变
// 指针与引用看上去完全不同(指针用操作符”*”和”->”，引用使用操作符”.”)，但是它们似乎有相同的功能。指针和引用都是让你间接引用其它对象。
// 在任何情况下都不能使用指向空值的引用。一个引用必须总是指向某些对象。在C++里，引用应被初始化。
// 不存在指向空值的引用这个事实意味着使用引用的代码效率比使用指针的要高。因为在使用引用之前不需要测试它的合法性。
// 指针与引用的另一个重要的不同是指针可以被重新赋值以指向另一个不同的对象。但是引用则总是指向在初始化时被指定的对象，以后不能改变。
// 总的来说，在以下情况下你应该使用指针，一是你考虑到存在不指向任何对象的可能(在这种情况下，你能够设置指针为空)，
// 二是你需要能够在不同的时刻指向不同的对象(在这种情况下，你能改变指针的指向)。
// 如果总是指向一个对象并且一旦指向一个对象后就不会改变指向，那么你应该使用引用。
// 当你知道你必须指向一个对象并且不想改变其指向时，或者在重载操作符并为防止不必要的语义误解时(最普通的例子是操作符[])，你不应该使用指针。而在除此之外的其它情况下，则应使用指针。



71.
// 静态初始化：在main执行前和执行后都有大量代码被执行。
// 尤其是，静态的类对象和定义在全局的、命名空间中的或文件体中的类对象的构造函数通常在main被执行前就被调用。这个过程称为静态初始化。
// 同样，通过静态初始化产生的对象也要在静态析构过程中调用其析构函数，这个过程通常发生在main结束运行之后。
// 动态内存分配：C++部分使用new和delete，C部分使用malloc(或其变形)和free。
// 数据结构的兼容性：在C++和C之间这样相互传递数据结构是安全的----在C++和C下提供同样的定义来进行编译。
// 在C++版本中增加非虚成员函数或许不影响兼容性，但几乎其它的改变都将影响兼容。
// 如果想在同一程序下混合C++与C编程，记住下面的指导原则：(1).确保C++和C编译器产生兼容的obj文件；
// (2).将在两种语言下都使用的函数声明为extern “C”；(3).只要可能，用C++写main()；
// (4).总用delete释放new分配的内存；总用free释放malloc分配的内存；
// (5).将在两种语言间传递的东西限制在用C编译的数据结构的范围内；这些结构的C++版本可以包含非虚成员函数。



72. 尽量使用C++风格的类型转换
// C++通过引进四个新的类型转换操作符克服了 C 风格类型转换的缺点,这四个操作符是,static_cast, const_cast, dynamic_cast, 和 reinterpret_cast
// static_cast 在功能上基本上与 C 风格的类型转换一样强大,含义也一样。它也有功能上限制
// const_cast 用于类型转换掉表达式的 const 或 volatileness 属性
// dynamic_cast,它被用于安全地沿着类的继承关系向下进行类型转换。这就是说,你能用 dynamic_cast 把指向基类的指针或引用转换成指向其派生类或其兄弟类的指针或引用,
// 而且你能知道转换是否成功。失败的转换将返回空指针(当对指针进行类型转换时)或者抛出异常(当对引用进行类型转换时)
// dynamic_casts 在帮助你浏览继承层次上是有限制的。它不能被用于缺乏虚函数的类型上,也不能用它来转换掉 
// 如你想在没有继承关系的类型中进行转换,你可能想到 static_cast。如果是为了去除const,你总得用 const_cast
// reinterpret_cast。使用这个操作符的类型转换,其 的 转 换 结 果 几 乎 都 是 执 行 期 定 义 ( implementation-defined )。 因 此 , 使 用reinterpret_casts 的代码很难移植
// reinterpret_casts 的最普通的用途就是在函数指针类型之间进行转换

// 像所有其他std::*_pointer_cast函数一样，这允许您在std::shared_ptr中包装的不同指针类型之间进行强制转换，就好像强制转换了原始指针一样，但保留了共享所有权

